package com.example.myapplication.scroller;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.ViewConfiguration;
import android.widget.OverScroller;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.LinearLayoutCompat;
import androidx.core.view.ViewConfigurationCompat;

public class CustomScrollerView extends LinearLayoutCompat {

    private static final String TAG = "Scroller";

    private OverScroller mScroller;
    private int mTouchSlop;
    private VelocityTracker mVelocityTracker;
    private int mScaledMinimumFlingVelocity;
    private int mScaledMaximumFlingVelocity;
    private GestureDetector gestureDetector;

    public CustomScrollerView(@NonNull Context context) {
        super(context);
        init();
    }

    public CustomScrollerView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CustomScrollerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }


    private void init() {
        mScroller = new OverScroller(getContext());
        ViewConfiguration configuration = ViewConfiguration.get(getContext());
        mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
        mScaledMinimumFlingVelocity = configuration.getScaledMinimumFlingVelocity();
        mScaledMaximumFlingVelocity = configuration.getScaledMaximumFlingVelocity();
        gestureDetector=new GestureDetector(getContext(),new GestureListener());

    }

    //调用此方法滚动到目标位置
    public void smoothScrollTo(int fx, int fy) {
        int dx = fx - mScroller.getFinalX();
        int dy = fy - mScroller.getFinalY();
        smoothScrollBy(dx, dy);
    }

    //调用此方法设置滚动的相对偏移
    public void smoothScrollBy(int dx, int dy) {
        smoothScrollBy(dx,dy,310);
    }

    //调用此方法设置滚动的相对偏移
    public void smoothScrollBy(int dx, int dy,int duration) {
        //设置mScroller的滚动偏移量
        Log.e(TAG, "*************************in the smoothScrollBy()*************************");
        logXYInfo();
        mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy,duration);
        logXYInfo();
        //这里必须调用invalidate()才能保证computeScroll()会被调用，否则不一定会刷新界面，看不到滚动效果
        invalidate();
        Log.e(TAG, "*************************end the smoothScrollBy()*************************");
    }



    @Override
    public void computeScroll() {
        Log.e(TAG, "in the computeScroll()");
        logXYInfo();
        //先判断mScroller滚动是否完成
        if (mScroller.computeScrollOffset()) {
            //这里调用View的scrollTo()完成实际的滚动
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            //必须调用该方法，否则不一定能看到滚动效果
            postInvalidate();
        }
        super.computeScroll();
    }

    float mXDown = 0;
    float mXLastMove=0;
    float mDistance=0;

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mXDown = ev.getRawX();
                mXLastMove = mXDown;
                break;
            case MotionEvent.ACTION_MOVE:
                float mXMove = ev.getRawX();
                mXLastMove = mXMove;
                // 当手指拖动值大于TouchSlop值时，认为应该进行滚动，拦截子控件的事件
                float diff = Math.abs(mXMove - mXDown);
                if (diff > mTouchSlop) {
                    log("diff > mTouchSlop****************************************************** -->  getRawX()=" + ev.getRawX() + "    event.getX()=" + ev.getX() + "    mXLastMove=" + mXLastMove);
                    return true;
                }
                break;
        }
        return super.onInterceptTouchEvent(ev);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {

        if (mVelocityTracker == null) mVelocityTracker = VelocityTracker.obtain();
        mVelocityTracker.addMovement(event);

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mXLastMove = event.getRawX();
                log("action down--> ======================================= getRawX()=" + event.getRawX() + "    event.getX()=" + event.getX() + "     mXDown=" + mXDown);
                return true;
            case MotionEvent.ACTION_UP:
                mVelocityTracker.computeCurrentVelocity(1000, mScaledMaximumFlingVelocity);
                int velocityX = (int)mVelocityTracker.getXVelocity();
                log("action up-->  getRawX()=" + event.getRawX() + "    event.getX()=" + event.getX()+"     velocityX="+velocityX);
                if(mVelocityTracker!=null){
                    mVelocityTracker.clear();
                    mVelocityTracker.recycle();
                    mVelocityTracker=null;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                mDistance= event.getRawX() - mXLastMove;
                log("action move-->    distance=" + mDistance + "   getRawX()=" + event.getRawX() + "    event.getX()=" + event.getX() + "    mXLastMove=" + mXLastMove + "      event.getRawX()=" + event.getRawX());
                mXLastMove = event.getRawX();
                smoothScrollBy((int) -mDistance, 0);
                break;
            case MotionEvent.ACTION_CANCEL:
                log("action cancel-->  getRawX()=" + event.getRawX() + "    event.getX()=" + event.getX());
                break;
        }
        return   gestureDetector.onTouchEvent(event);
    }


    private class GestureListener extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            log("--------------------------------------------onFling  -----------------------");
            log("--------------------------------------------velocityX="+velocityX+"-----------");
            log("--------------------------------------------velocityY="+velocityY+"-----------");
            return super.onFling(e1, e2, velocityX, velocityY);
        }

        @Override
        public void onLongPress(MotionEvent e) {
            super.onLongPress(e);
            log("--------------------------------------------onLongPress()-----------------------");
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            log("--------------------------------------------onScroll()  distanceX="+distanceX+"   mDistance="+mDistance+"-----------------------");
            return super.onScroll(e1, e2, distanceX, distanceY);
        }

        @Override
        public void onShowPress(MotionEvent e) {
            super.onShowPress(e);
            log("--------------------------------------------onShowPress()-----------------------");
        }

        @Override
        public boolean onDown(MotionEvent e) {
            log("--------------------------------------------onDown()  -----------------------");
            return super.onDown(e);
        }
    }

    private void logXYInfo() {
        Log.e(TAG, "getScrollX():" + getScrollX() + "    mScroller.getFinalX(): " + mScroller.getFinalX());
    }

    private void log(String msg) {
        Log.e(TAG, msg);
    }
}
